package com.mimo.logic.user.controller;

import static com.mimo.logic.user.model.QUserInfo.userInfo;

import java.util.Objects;

import javax.validation.Valid;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.mimo.common.comet.dto.ZoneDTO;
import com.mimo.common.comet.dto.user.DeviceDTO;
import com.mimo.common.comet.dto.user.UserLoginReq;
import com.mimo.common.configuration.broadcast.MultiCastRegistry;
import com.mimo.common.configuration.security.rbac.annotation.AccessFor;
import com.mimo.common.logic.code.StatusCode;
import com.mimo.common.logic.user.dto.UserDTO;
import com.mimo.common.logic.user.dto.UserQueryCriteria;
import com.mimo.common.result.BaseResult;
import com.mimo.common.result.CollectionResult;
import com.mimo.common.result.CommonDTOResult;
import com.mimo.logic.event.UserStatusActionEvent;
import com.mimo.logic.event.UserStatusActionType;
import com.mimo.logic.user.dao.IUserDao;
import com.mimo.logic.user.model.UserInfo;
import com.mimo.logic.user.service.IUserService;
import com.querydsl.core.types.dsl.BooleanExpression;

import io.swagger.annotations.ApiOperation;

@Validated
@RestController
@RequestMapping("/user")
public class UserController {

  @Autowired
  private IUserService userService;

  @Autowired
  private IUserDao userDao;

  @PostMapping(value = "/admin/query")
  @ApiOperation(value = "后台用户接口查询", response = UserDTO.class)
  public BaseResult query(@RequestBody UserQueryCriteria criteria) {
    BooleanExpression e = userInfo.uid.isNotNull();
    if (StringUtils.hasText(criteria.getUserId())) {
      e = e.and(userInfo.uid.eq(criteria.getUserId()));
    }

    if (Objects.nonNull(criteria.getBegin())) {
      e = e.and(userInfo.createdDate.gt(criteria.getBegin()));
    }

    if (Objects.nonNull(criteria.getEnd())) {
      e = e.and(userInfo.createdDate.lt(criteria.getEnd()));
    }

    if (Objects.nonNull(criteria.getLoginBegin())) {
      e = e.and(userInfo.loginDate.gt(criteria.getLoginBegin()));
    }

    if (Objects.nonNull(criteria.getLoginEnd())) {
      e = e.and(userInfo.loginDate.lt(criteria.getLoginEnd()));
    }

    if (Objects.nonNull(criteria.getOnline())) {
      e = e.and(userInfo.online.eq(criteria.getOnline()));
    }
    Page<UserDTO> us = userDao
        .findAll(e, PageRequest.of(criteria.getPage(), criteria.getSize(), Sort.by(Direction.DESC, "loginDate")))
        .map(this::convert);
    return new CollectionResult<>(us.getContent(), us.getTotalElements());
  }

  @GetMapping(value = "/admin/load")
  @ApiOperation(value = "后台查看指定用户信息", response = UserDTO.class)
  public BaseResult adminLoad(@RequestParam String userId) {
    return new CommonDTOResult<>(convert(userService.load(userId)));
  }

  private UserDTO convert(UserInfo info) {
    UserDTO dto = new UserDTO();
    BeanUtils.copyProperties(info, dto, "zone", "device");
    dto.setCreatedDate(info.getCreatedDate());
    dto.setLoginDate(info.getLoginDate());

    ZoneDTO zone = new ZoneDTO();
    if (Objects.nonNull(info.getZone())) { // 用户从来没有登陆过，则zone关联为空
      BeanUtils.copyProperties(info.getZone(), zone);
    } else {
      zone.setIp("-");
      zone.setName("-");
      zone.setPort(-1);
    }

    DeviceDTO device = new DeviceDTO();
    if (Objects.nonNull(info.getDevice())) {
      BeanUtils.copyProperties(info.getDevice(), device);
    }

    dto.setZone(zone);
    dto.setDevice(device);
    return dto;
  }

  @AccessFor
  @PostMapping(value = "/generate")
  @ApiOperation(value = "刷新或者创建账户", response = UserInfo.class)
  public BaseResult generate(@RequestParam String userId) {
    return new CommonDTOResult<>(userService.generate(userId));
  }

  @PostMapping(value = "/login")
  @ApiOperation(value = "外部登陆接口", response = Boolean.class)
  public BaseResult login(@RequestBody @Valid UserLoginReq req) {
    StatusCode statusCode = userService.login(req);
    if (statusCode.isSuccess()) {
      MultiCastRegistry.INSTANCE
          .publish(new UserStatusActionEvent(this, userService.load(req.getUid()), UserStatusActionType.Login));
    }
    return new CommonDTOResult<>(statusCode.isSuccess());
  }

  @PostMapping(value = "/logout")
  @ApiOperation(value = "退登", response = Boolean.class)
  public BaseResult logout(@RequestParam String userId) {
    MultiCastRegistry.INSTANCE
        .publish(new UserStatusActionEvent(this, userService.load(userId), UserStatusActionType.Logout));
    return BaseResult.SUCCESS_RET;
  }

  @GetMapping(value = "/load")
  @ApiOperation(value = "想看用户账户信息及其所属区域", response = UserInfo.class)
  public BaseResult load(@RequestParam String userId) {
    return new CommonDTOResult<>(userService.load(userId));
  }

}
